package agent;
import java.util.ArrayList;
import java.util.Hashtable;

import dao.DaoAgente;

import jade.core.Agent;
import jade.core.behaviours.Behaviour;
import jade.core.behaviours.SequentialBehaviour;
import jade.lang.acl.ACLMessage;
import model.Coordenada;
import model.Rota;
import model.Shape;
import model.Stop;
import model.SubRota;



public class AgBuscador extends Agent{
	
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Coordenada origemIni;
	private Coordenada destino;
	private Stop stopOrigem;
	
	
	
	protected void setup(){
		
		
		SequentialBehaviour seq = new SequentialBehaviour(this){//composto

			private static final long serialVersionUID = 1L;

			public int onEnd(){
				myAgent.doDelete();
				return 0;
			}
			
		};
		
		seq.addSubBehaviour(new Behaviour(this){ //recebe mensagen com os dados da busca
			
			private static final long serialVersionUID = 1L;
			 Hashtable obj; 
			public void action(){
				System.out.println("Exec comportamento...RECEBE MSG"+myAgent.getName());
				ACLMessage msg = receive();
				if(msg !=null){
					try{
						obj = new Hashtable();
						obj =  (Hashtable) msg.getContentObject();
						origemIni = (Coordenada) obj.get("origem");
						destino = (Coordenada) obj.get("destino");
						stopOrigem = (Stop) obj.get("stopOrigem");
						
						//teste
						System.out.println("COMPORTAMENTO BUSCA ROTA "+getName());
						System.out.println("Lat origem" +origemIni.getLat());
						System.out.println("Lat destino" +destino.getLat());
						System.out.println("Lat stopOrigem nome" +stopOrigem.getStop_name());
					}catch(Exception e){
						e.printStackTrace();
					}
				}
				
			}
			
			public boolean done(){
				if(this.obj == null){
					block();
					return false;
				}
				else
					return true;
				
			}
		});//fim do recebe mensagem
				
		
		seq.addSubBehaviour(new Behaviour(this){  //busca rotas
			
			ArrayList<Rota> rotas = new ArrayList<Rota>();
			ArrayList<Rota> rotasOk = new ArrayList<Rota>();
			ArrayList<SubRota> subRotas = new ArrayList<SubRota>();
			Stop stopDestino = new Stop();
			DaoAgente dao = new DaoAgente();
	
			@Override
			public void action() {
				block();
				System.out.println("Exec comportamento...bUSCA ROTA"+myAgent.getName());
				rotas = buscar(origemIni, destino, stopOrigem, stopDestino, subRotas);
				
				System.out.println("Numero de rotas devolvidas pela função: "+rotas.size());
				System.out.println("Adicionar rotas ----------"+myAgent.getName());
				for(int i = 0; i<rotas.size(); i++){
					System.out.println("Adicionar rota num:"+i+" na área por "+myAgent.getName());
					AreaRotas.addRota(rotas.get(i));
					System.out.println("Numero de rotas na área: "+AreaRotas.getNumRotas());
				}
				
				//System.out.println("Numero de rotas na área: "+AreaRotas.getNumRotas());
				takeDown();
			}

			@Override
			public boolean done() {
//				if(AreaRotas.getNumRotas() > 5){
//					return true;
//				}
				
				return false;
			}
			
			public ArrayList<Stop> buscaRaioOrigem(Coordenada origem, Coordenada destino){
				int raioOrigem = 0;
				ArrayList<Stop> stopsOrigem = new ArrayList<Stop>();
				//pegando pontos no raio de origem (aumentando o raio de origem até encontrar)
				while(stopsOrigem.size() == 0){
					raioOrigem++;
					stopsOrigem = dao.getStopsOfCoordRaio(origem.getLat(), origem.getLon(), raioOrigem);
					
					/*VERIFICAR SE A DISTANCIA À PÉ DO STOP ENCONTRADO PARA ORIGEM É SUPERIOR A DISTÂNCIA À PE ENTRE ORIGEM E DESTINO!!!!*/
					
				}
				return stopsOrigem;
			}
			
			public ArrayList<Rota> buscar(Coordenada origem, Coordenada destino, Stop stopOrigem, Stop stopDestino, ArrayList<SubRota> subRotas){
				ArrayList<Stop> stopsOrigem = new ArrayList<Stop>();
				
				if(origemIni.getLat() != origem.getLat() || origemIni.getLon() != origem.getLon()){
					stopsOrigem = buscaRaioOrigem(origem, destino);
				}
				else{
					stopsOrigem.add(stopOrigem);
				}
				
				for(int st = 0; st < stopsOrigem.size(); st++){
					stopOrigem = stopsOrigem.get(st);
					
					int raioDestino = 0;
					ArrayList<String> trips = new ArrayList<String>();
					boolean raioDestinoTocou = false;
					//DaoAgente dao = new DaoAgente();
					double distDestOrig = destino.calculaDistancia(origem.getLat(), origem.getLon());
					
					
					
					
					//busca viagens no stop de origem
					while(trips.size() == 0){
						
						raioDestino++;
						trips = dao.getTripsOfStopCoordRaio(stopOrigem.getStop_id(), destino.getLat(), destino.getLon(), raioDestino);
					}
					
					for(int t = 0; t < trips.size(); t++){
						//verifica se outro agente já esta nesta linha
						if(AreaRotas.getTrips().contains(trips.get(t))){
							//System.out.println("Outro agente ja esta buscando na linha "+trips.get(t));
							continue;
						}
						AreaRotas.getTrips().add(trips.get(t));
						//busca repetição na rota
						if(verificaRepeticao(trips.get(t), subRotas)){
							System.out.println("Estou andando em circulos, descartando viagem "+trips.get(t));
							continue;
						}
						
						int raioShape = 0;
						//ArrayList<Stop> stopsOrigem = new ArrayList<Stop>();
						ArrayList<Stop> stopsDestino = new ArrayList<Stop>();
						ArrayList<Shape> forma = new ArrayList<Shape>();
						Shape shapeOrigem = new Shape();
						Shape shapeDestino = new Shape();
						SubRota srt = new SubRota();
						if(raioDestinoTocou)
							break;
						stopOrigem = dao.getStopOfTripStopId(trips.get(t), stopOrigem.getStop_id());
						
						//pegando stops no destino, da viagem de indice t
						stopsDestino = dao.getStopsOfCoordRaio(trips.get(t), destino.getLat(), destino.getLon(), raioDestino);
						
						
						//testando se raio tocou
						for(int i = 0; i < stopsDestino.size(); i++){
							if(stopOrigem.getStop_id() == stopsDestino.get(i).getStop_id()){
								raioDestinoTocou = true;
								break;
							}
						}
						
						if(raioDestinoTocou)
							break;
						
						
						//eliminando os stops do destino de direção contraria
						ArrayList<Stop> stopsDestinoTemp = new ArrayList<Stop>();
						for(int i = 0; i < stopsDestino.size(); i++){
							if(stopOrigem.getStop_sequence() < stopsDestino.get(i).getStop_sequence()){
								stopsDestinoTemp.add(stopsDestino.get(i));
							}
						}
						if(stopsDestinoTemp.size() == 0){
							continue;
						}
						else{
							stopsDestino = stopsDestinoTemp;
							//identificando o stop mais próximo do destino
							stopDestino = stopsDestino.get(0);
							double distStopDestino;
							double distStopDestinoTeste;
							for(int i = 0; i < stopsDestino.size(); i++){
								distStopDestino = destino.calculaDistancia(stopDestino.getStop_lat(), stopDestino.getStop_lon());
								distStopDestinoTeste = destino.calculaDistancia(stopsDestino.get(i).getStop_lat(), stopsDestino.get(i).getStop_lon());
								if(distStopDestinoTeste < distStopDestino){
									stopDestino = stopsDestino.get(i);
								}
							}
							double distDestStDest = destino.calculaDistancia(stopDestino.getStop_lat(), stopDestino.getStop_lon());
							if(distDestStDest > distDestOrig){
								continue;
							}
							
							//Aqui já tenho "stopOrigem" e "stopDestino" com linha viagem.
							
							
							///buscando Shapes de origem
							ArrayList<Shape> shapesOrigem = new ArrayList<Shape>();
							for(raioShape = 1; shapesOrigem.size() == 0; raioShape++){
								shapesOrigem = dao.getShapesOfTripCoordRaio(trips.get(t), stopOrigem.getStop_lat(), stopOrigem.getStop_lon(), raioShape);
							}
							
							//encontrando shape mais pròximo do stop de Origem
							Coordenada coordStopOrig = new Coordenada(stopOrigem.getStop_lat(), stopOrigem.getStop_lon());
							shapeOrigem = shapesOrigem.get(0);
							double distShapeOrigem;
							double distShapeOrigemTeste;
							for(int i = 0; i < shapesOrigem.size(); i++){
								distShapeOrigem = coordStopOrig.calculaDistancia(shapeOrigem.getShape_pt_lat(), shapeOrigem.getShape_pt_lon());
								distShapeOrigemTeste = coordStopOrig.calculaDistancia(shapesOrigem.get(i).getShape_pt_lat(), shapesOrigem.get(i).getShape_pt_lon());
								if(distShapeOrigemTeste < distShapeOrigem){
									shapeOrigem = shapesOrigem.get(i);
								}
							}
							
							
							
							///buscando Shapes de Destino
							ArrayList<Shape> shapesDestino = new ArrayList<Shape>();
							for(raioShape = 1; shapesDestino.size() == 0; raioShape++){
								shapesDestino = dao.getShapesOfTripCoordRaio(trips.get(t), stopDestino.getStop_lat(), stopDestino.getStop_lon(), raioShape);
							}
							
							//encontrando shape mais pròximo do stop de Destino
							Coordenada coordStopDest = new Coordenada(stopDestino.getStop_lat(), stopDestino.getStop_lon());
							shapeDestino = shapesDestino.get(0);
							double distShapeDestino;
							double distShapeDestinoTeste;
							for(int i = 0; i < shapesDestino.size(); i++){
								distShapeDestino = coordStopDest.calculaDistancia(shapeDestino.getShape_pt_lat(), shapeDestino.getShape_pt_lon());
								distShapeDestinoTeste = coordStopDest.calculaDistancia(shapesDestino.get(i).getShape_pt_lat(), shapesDestino.get(i).getShape_pt_lon());
								if(distShapeDestinoTeste < distShapeDestino){
									shapeDestino = shapesDestino.get(i);
								}
							}
							
							///Aqui já tenho "shapeOrigem" e "shapeDestino" com linha viagem.
							
							
							//buscando forma da subrota para ser desenhada
							if(shapeOrigem.getShape_id() == shapeDestino.getShape_id()){
								forma = dao.getShapesOfTripOrigemDestino(shapeOrigem.getShape_id(), shapeOrigem.getShape_pt_sequence(), shapeDestino.getShape_pt_sequence());
							}
							else{
								System.out.println("SHAPE DE ORIGEM ID DIFERENTE DO SHAPE DE DESTINO ID!!!!!");
								continue;
							}
							if(forma.size() > 0){
								System.out.println("Montando SubRota");
								srt.setForma(forma);
								srt.setStopOrigem(stopOrigem);
								srt.setStopDestino(stopDestino);
								srt = dao.preencheSubrota(trips.get(t), srt);
								System.out.println("Add SubRota");
								ArrayList<SubRota> subRotasNova = new ArrayList<SubRota>();
								subRotasNova = subRotas;
								subRotasNova.add(srt);
								
								
								if(raioDestino <= 2){
									Rota rota = new Rota();
									System.out.println("Raio < 2 Add rota");
									rota.setSubrotas(subRotasNova);
									//AreaRotas.addRota(rota);
									rotas.add(rota);
									continue;
//							block();
//							this.rotas.add(rota);
//							return rotas;
								}
								else{
									//subRotasNova.add(srt);
									//recurção
									Coordenada novaOrigem = new Coordenada(stopDestino.getStop_lat(), stopDestino.getStop_lon());
									Stop novoStopOrigem = stopDestino;
									Stop novoStopDestino = new Stop();
									System.out.println("Recurção");
									buscar(novaOrigem, destino, novoStopOrigem, novoStopDestino, subRotasNova);
								}
								
							}
							continue;
						}
						
					}
				}
				
//				if(subRotas.size() > 0){
//					
//					rota.setSubrotas(subRotas);
//					AreaRotas.addRota(rota);
//				}else{
//					
//				}
//				block();
//				this.rotas.add(rota);
				return rotas;
					
			}
			
			public boolean verificaRepeticao(String tripId, ArrayList<SubRota> subRotas){
				for(int i = 0; i < subRotas.size(); i++){
					
					if(subRotas.get(i).getViagem().equals(tripId)){
						return true;
					}
				}
				return false;
			}
			
			
			public boolean toucouRaio(ArrayList<String> trips, double lat, double lon, int raioDestino, Stop stopOrigem){
				boolean tocaRaio = false;
				DaoAgente dao = new DaoAgente();
				//pegando stops no destino, da viagem de indice t
				for(int t = 0; t < trips.size(); t++){
					ArrayList<Stop> stopsDestino = dao.getStopsOfCoordRaio(trips.get(t), destino.getLat(), destino.getLon(), raioDestino);
					
					//Verificando se o raio destino tocou o stopOrigem
					for(int i = 0; i < stopsDestino.size(); i++){
						
						if((stopOrigem.getStop_lat() == stopsDestino.get(i).getStop_lat()) && (stopOrigem.getStop_lon() == stopsDestino.get(i).getStop_lon())){
							tocaRaio = true;
						}
						
					}
					if(tocaRaio){
						return tocaRaio;
					}
				}
				return tocaRaio;
				
			}
			
			//gets e sets
				public ArrayList<Rota> getRotas() {
					return rotas;
				}

				public void setRotas(ArrayList<Rota> rotas) {
					this.rotas = rotas;
				}
				
		}); 
				
				
				
				
				
				
//CpBuscaRota(this, origem, destino, stopOrigem));
			
		addBehaviour(seq);

		
		
	}
	
	protected void takeDown(){
		AreaRotas.addNumBuscas();
//		System.out.println("Numero de rotas = "+AreaRotas.getNumRotas());
//		ArrayList<Rota> rotas = AreaRotas.getRotas();
//		System.out.println("Rotas: "+rotas.size());
//		for(int i=0; i<rotas.size(); i++){
//			System.out.println("Numero da Rota: "+(i+1)+"\t\t\tNumero de Subrotas: "+rotas.get(i).getSubrotas().size());
//			for(int j=0; j<rotas.get(i).getSubrotas().size(); j++){
//				System.out.println("Numero da Rota: "+(i+1)+"\t\t\tSubrota numero: "+(j+1));
//				System.out.println("ID do ponto de origem: "+rotas.get(i).getSubrotas().get(j).getStopOrigem().getStop_id());
//				System.out.println("ID do ponto de destino: "+rotas.get(i).getSubrotas().get(j).getStopDestino().getStop_id());
//				System.out.println("Origem LAT: "+rotas.get(i).getSubrotas().get(j).getOrigem().getLat()+"\t\t\tOrigem LON: "+rotas.get(i).getSubrotas().get(j).getOrigem().getLon());
//				System.out.println("Destino LAT: "+rotas.get(i).getSubrotas().get(j).getDestino().getLat()+"\t\tDestino LON: "+rotas.get(i).getSubrotas().get(j).getDestino().getLon());
//				System.out.println("Distancia: "+rotas.get(i).getSubrotas().get(j).getDistancia());
//				System.out.println("Viagem: "+rotas.get(i).getSubrotas().get(j).getViagem());
//				System.out.println("Linha: "+rotas.get(i).getSubrotas().get(j).getLinha());
//				System.out.println("Descri��o: "+rotas.get(i).getSubrotas().get(j).getDescricaoLong());
//				System.out.println("Tipo: "+rotas.get(i).getSubrotas().get(j).getTipo());
//				System.out.printf("Tarifa: R$ %.2f\n",rotas.get(i).getSubrotas().get(j).getTarifa());
//				System.out.println("Cor: "+rotas.get(i).getSubrotas().get(j).getCor());
//			}
//		}
		System.out.println("Agente: "+getAID().getName()+" esta fianlizado...");
		
	}
	
	
	

}
